package top100.dynamic;

import java.util.Scanner;

/**
 * @Author ZhangCuirong
 * @Date 2025/7/21 11:23
 * @description:
 * 小明是一位科学家，他需要参加一场重要的国际科学大会，以展示自己的最新研究成果。他需要带一些研究材料，但是他的行李箱空间有限。这些研究材料包括实验设备、文献资料和实验样本等等，它们各自占据不同的重量，并且具有不同的价值。
 *
 * 小明的行李箱所能承担的总重量是有限的，问小明应该如何抉择，才能携带最大价值的研究材料，每种研究材料可以选择无数次，并且可以重复选择。
 *
 * 输入描述
 * 第一行包含两个整数，n，v，分别表示研究材料的种类和行李所能承担的总重量
 *
 * 接下来包含 n 行，每行两个整数 wi 和 vi，代表第 i 种研究材料的重量和价值
 *
 * 输出描述
 * 输出一个整数，表示最大价值。
 * 输入示例
 * 4 5
 * 1 2
 * 2 4
 * 3 4
 * 4 5
 * 输出示例
 * 10
 * 提示信息
 * 第一种材料选择五次，可以达到最大值。
 *
 * 数据范围：
 *
 * 1 <= n <= 10000;
 * 1 <= v <= 10000;
 * 1 <= wi, vi <= 10^9.
 * 	    重量	价值
 * 物品0	1	15
 * 物品1	3	20
 * 物品2	4	30
 */
public class Main2 {
    public int bag(int[] weight, int[] value, int w) {
        int[][] dp = new int[weight.length][w + 1];

        for (int j = weight[0]; j <= w; j++) {
            dp[0][j] = value[0] * (j / weight[0]);
        }
//        for (int j = weight[0]; j <= w; j++) {
//            dp[0][j] = dp[0][j - weight[0]] + value[0];
//        }
        for (int i = 1; i < weight.length; i++) {
            for (int j = 0; j <= w; j++) {
                if (j >= weight[i]) {
                    dp[i][j] = Math.max(dp[i][j - weight[i]] + value[i], dp[i - 1][j]);
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        return dp[weight.length - 1][w];
    }
    public int bag2(int[] weight, int[] value, int w){
        int[][] dp = new int[weight.length][w + 1];

//        for (int j = weight[0]; j <= w; j++) {
//            dp[0][j] = value[0] * (j / weight[0]);
//        }
        for (int j = weight[0]; j <= w; j++) {
            dp[0][j] = dp[0][j - weight[0]] + value[0];
        }

        for (int j = 0; j <= w; j++) {
            for (int i = 1; i < weight.length; i++) {
                if (j >= weight[i]) {
                    dp[i][j] = Math.max(dp[i][j - weight[i]] + value[i], dp[i - 1][j]);
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        return dp[weight.length - 1][w];
    }
    public int bag3(int[] weight, int[] value, int w){
        //倒序遍历是为了保证物品i只被放入一次！。但如果一旦正序遍历了，那么物品0就会被重复加入多次！
        int[] dp = new int[w + 1];

        for (int j = weight[0]; j <= w; j++) {
            dp[j] = dp[j - weight[0]] + value[0];
        }
        for (int i = 1; i < weight.length; i++) {
            for (int j = weight[i]; j <=w; j++) {
                if (j >= weight[i]) {
                    dp[j] = Math.max(dp[j - weight[i]] + value[i], dp[j]);
                }
            }
        }
        return dp[w];
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int M = sc.nextInt();
        int N = sc.nextInt();
        int[] weight = new int[M + 1];
        int[] value = new int[M + 1];
        for (int i = 0; i < M; i++) {
            weight[i] = sc.nextInt();
            value[i] = sc.nextInt();
        }
        Main2 main = new Main2();
        int res = main.bag3(weight, value, N);
        System.out.println(res);
    }
}
